/*  mudmap - A tool to create and organize user side maps for MUD games
 *  Copyright (C) 2012  Neop (aka moemneop, email: mneop@web.de)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/*  File description
 *
 *  A simple way to code tables that can use negative key values (probably slow) :B
 */

#pragma once

#include <unordered_map>
#include <memory>

using namespace std;

template<class T>
class table{
    public:
        table();
        virtual ~table();

        void set(shared_ptr<T> data, int x, int y);
        void set(shared_ptr<T> data, pair<int, int> pos);
        void remove(int x, int y);
        shared_ptr<T> get(int x, int y);
        void insert_row(int row, int cnt = 1);
        void insert_column(int column, int cnt = 1);
        int remove_row(int row);
        int remove_column(int column);
        void clean();

        unordered_map<int, unordered_map<int, shared_ptr<T> > > data;
    private:
};

template<class T>
table<T>::table(){
}

template<class T>
table<T>::~table(){
}

template<class T>
void table<T>::set(shared_ptr<T> data, int x, int y){
    (this->data[x])[y] = data;
}

template<class T>
void table<T>::set(shared_ptr<T> data, pair<int, int> pos){
    (this->data[pos.first])[pos.second] = data;
}

template<class T>
void table<T>::remove(int x, int y){
    (data[x])[y] = nullptr;
}

template<class T>
shared_ptr<T> table<T>::get(int x, int y){
    return (data[x])[y];
}

template<class T>
void table<T>::insert_column(int column, int cnt){
    unordered_map<int, unordered_map<int, shared_ptr<T> > > data_new;
    int x, y;
    for(auto itx = data.begin(); itx != data.end(); itx++){
        for(auto ity = itx->second.begin(); ity != itx->second.end(); ity++){
            x = itx->first;
            y = ity->first;
            if(column >= 0){
                if(itx->first >= column) x += cnt;
            } else if(itx->first <= column) x -= cnt;
            data_new[x][y] = ity->second;
        }
    }
    data = data_new;
}

template<class T>
void table<T>::insert_row(int row, int cnt){
    unordered_map<int, unordered_map<int, shared_ptr<T> > > data_new;
    int x, y;
    for(auto itx = data.begin(); itx != data.end(); itx++){
        for(auto ity = itx->second.begin(); ity != itx->second.end(); ity++){
            x = itx->first;
            y = ity->first;
            if(row >= 0){
                if(ity->first >= row) y += cnt;
            } else if(ity->first <= row) y -= cnt;
            data_new[x][y] = ity->second;
        }
    }
    data = data_new;
}

template<class T>
int table<T>::remove_column(int column){
    unordered_map<int, unordered_map<int, shared_ptr<T> > > data_new;
    int cnt = 0, x, y;
    for(auto itx = data.begin(); itx != data.end(); itx++){
        for(auto ity = itx->second.begin(); ity != itx->second.end(); ity++){
            x = itx->first;
            y = ity->first;
            if(column >= 0){
                if(itx->first > column) x--;
            } else if(itx->first < column) x++;
            if(ity->second != nullptr && itx->first == column) cnt++;
            else if(column != itx->first) data_new[x][y] = ity->second;
        }
    }
    data.clear();
    data = data_new;
    return cnt;
}

template<class T>
int table<T>::remove_row(int row){
    unordered_map<int, unordered_map<int, shared_ptr<T> > > data_new;
    int cnt = 0, x, y;
    for(auto itx = data.begin(); itx != data.end(); itx++){
        for(auto ity = itx->second.begin(); ity != itx->second.end(); ity++){
            x = itx->first;
            y = ity->first;
            if(row >= 0){
                if(ity->first > row) y--;
            } else if(ity->first < row) y++;
            if(ity->second != nullptr && ity->first == row) cnt++;
            else if(row != ity->first) data_new[x][y] = ity->second;
        }
    }
    data.clear();
    data = data_new;
    return cnt;
}
/// TODO: \- bugt weil die gespeicherte place pos in der place klasse nicht geändert wird!

template<class T>
void table<T>::clean(){
    data.clear();
}
